﻿using Hx.ADSyncPlatform.ActiveDirectory.Attributes;
using Hx.ADSyncPlatform.ActiveDirectory.Model;
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Linq;

namespace Hx.ADSyncPlatform.ActiveDirectory.Access
{
    /// <summary>
    /// 组织访问
    /// </summary>
    internal class OrganizationAccess
    {

        public SearchResult SingleByDistinguishedName(DirectoryEntry rootEntry, string distinguishedName)
        {
            string filter = string.Format("(&(objectclass=organizationalUnit)(distinguishedName={0}))", distinguishedName);
            DirectorySearcher dsearcher = new DirectorySearcher(rootEntry, filter, null, SearchScope.Subtree);
            SearchResult result = dsearcher.FindOne();
            return result;
        }
        /// <summary>
        /// 组织
        /// </summary>
        /// <param name="rootEntry">查询的根AD对象</param>
        /// <param name="cn">Cn值</param>
        /// <returns>单个组织</returns>
        public SearchResult Single(DirectoryEntry rootEntry, string cn, SearchScope searchScope = SearchScope.Subtree)
        {
            string filter = string.Format("(&(objectclass=organizationalUnit)(cn={0}))", cn);
            DirectorySearcher dsearcher = new DirectorySearcher(rootEntry, filter, null, searchScope);
            SearchResult result = dsearcher.FindOne();
            return result;
        }
        /// <summary>
        /// 组织
        /// </summary>
        /// <param name="rootEntry">查询的根AD对象</param>
        /// <param name="cn">Cn值</param>
        /// <returns>单个组织</returns>
        public SearchResult SingleByOU(DirectoryEntry rootEntry, string ou, SearchScope searchScope = SearchScope.OneLevel)
        {
            string filter = string.Format("(&(objectclass=organizationalUnit)(ou={0}))", ou);
            DirectorySearcher dsearcher = new DirectorySearcher(rootEntry, filter, null, searchScope);
            SearchResult result = dsearcher.FindOne();
            return result;
        }


        /// <summary>
        /// 组织
        /// </summary>
        /// <param name="rootEntry">查询的根AD对象</param>
        /// <param name="cn">Cn值</param>
        /// <returns>单个组织</returns>
        public DirectoryEntry GetBrotherOrg(DirectoryEntry rootEntry, string targetOu)
        {
            try
            {
                var findOne = rootEntry.Children.Find($"OU={targetOu}");
                return findOne;
            }
            catch (Exception ex)
            {

                return null;
            }

        }
        /// <summary>
        /// 查询组织
        /// 名称模糊查询
        /// </summary>
        /// <param name="rootEntry">查询的根AD对象</param>
        /// <param name="name">组织名称</param>
        /// <returns>返回组织SearchResultCollection</returns>
        public SearchResultCollection Get(DirectoryEntry rootEntry, string name)
        {
            string filter = string.Format("(&(objectclass=organizationalUnit)(name={0}*))", name);
            DirectorySearcher dsearcher = new DirectorySearcher(rootEntry, filter, null, SearchScope.Subtree);
            SearchResultCollection result = dsearcher.FindAll();
            return result;
        }

        /// <summary>
        /// 查询组织
        /// 名称、显示名的模糊查询
        /// </summary>
        /// <param name="rootEntry">查询的根AD对象</param>
        /// <param name="name">组织名称</param>
        /// <param name="displayName">显示名</param>
        /// <returns>返回组织SearchResultCollection</returns>
        public SearchResultCollection Get(DirectoryEntry rootEntry, string name, string displayName)
        {
            string filter = string.Format("(&(objectclass=organizationalUnit)(|(name={0}*)(displayName={1}*)))", name, displayName);
            DirectorySearcher dsearcher = new DirectorySearcher(rootEntry, filter, null, SearchScope.Subtree);
            SearchResultCollection result = dsearcher.FindAll();
            return result;
        }

        /// <summary>
        /// 查询组织下的组织
        /// </summary>
        /// <param name="org">所在组织</param>
        /// <param name="searchScope">查询层级</param>
        /// <returns>返回用户SearchResultCollection</returns>
        public SearchResultCollection Get(DirectoryEntry org, SearchScope searchScope, List<string> excludeOrgs = null)
        {

            string filter = "(objectclass=organizationalUnit)";
            if (excludeOrgs != null && excludeOrgs.Any())//排除调指定org
            {
                string excludeFilter = "";
                foreach (string excludeStr in excludeOrgs)
                {
                    excludeFilter += $"(!(cn={excludeStr}))";
                }
                filter = $"(&(objectclass=organizationalUnit){excludeFilter})";
            }
            DirectorySearcher dsearcher = new DirectorySearcher(org, filter, null, searchScope);
            SearchResultCollection result = dsearcher.FindAll();
            return result;
        }

        /// <summary>
        /// 自定义查询
        /// </summary>
        /// <param name="rootEntry">查询的根AD对象</param>
        /// <param name="filter">LDAP查询语句</param>
        /// <param name="propertiesToLoad">需要返回的属性</param>
        /// <param name="searchScope">查询层级</param>
        /// <param name="pageSize">最大条数</param>
        /// <returns>返回用户SearchResultCollection</returns>
        public SearchResultCollection Search(DirectoryEntry rootEntry, string filter, List<string> propertiesToLoad, SearchScope searchScope, int pageSize = 0)
        {
            DirectorySearcher dsearcher = new DirectorySearcher(rootEntry, filter, propertiesToLoad?.ToArray(), searchScope);
            if (pageSize > 0)
            {
                //hack:确定分页代码可用？
                dsearcher.PageSize = pageSize;
            }
            SearchResultCollection searchResult = dsearcher.FindAll();
            return searchResult;
        }

        /// <summary>
        /// 创建组织
        /// </summary>
        /// <param name="orgDe">组织创建的组织</param>
        /// <param name="org">组织信息</param>
        /// <returns>成功True，失败False</returns>
        public bool Create(DirectoryEntry orgDe, Organization org)
        {
            if (string.IsNullOrWhiteSpace(org.CN))
                throw new ArgumentNullException($"创建组织时【CN】是必要属性，不能为空。");
            if (string.IsNullOrWhiteSpace(org.Ou))
                throw new ArgumentNullException($"创建组织时【Ou】是必要属性，不能为空。");

            var de = orgDe.Children.Add("OU=" + org.Ou, "organizationalUnit");
            foreach (var property in org.GetType().GetProperties())
            {
                if (org.AssignedAttributes.Contains(property.Name))
                {
                    var attributes = property.GetCustomAttributes(typeof(ReadOnlyCustomAttribute), false);
                    var mustCreate = property.GetCustomAttributes(typeof(RequiredForCreateAttribute), false);
                    var v = property.GetValue(org, null);
                    //判断创建时必须的字段是否为空
                    if (mustCreate != null && mustCreate.Any() && v == null)
                    {
                        throw new ArgumentNullException($"创建组织时【{property.Name}】是必要属性，不能为空。");
                    }

                    if (attributes == null || attributes.Length == 0)
                    {
                        //if (v == null)
                        //{
                        //    de.Properties[property.Name].Clear();
                        //}
                        //else
                        //{
                        //    de.Properties[property.Name].Value = v;
                        //}
                        if (v != null)
                        {
                            de.Properties[property.Name].Value = v;
                        }
                    }
                }
            }
            de.CommitChanges();
            return true;
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="orgDe">原始组织</param>
        /// <param name="org">新修改的组织信息</param>
        /// <returns>成功True，失败False</returns>
        public bool Update(DirectoryEntry orgDe, Organization org)
        {
            foreach (var property in org.GetType().GetProperties())
            {
                if (org.AssignedAttributes.Contains(property.Name))
                {
                    var notUpdate = property.GetCustomAttributes(typeof(IgnoreUpdateAttribute), false);
                    var readOnlyCustom = property.GetCustomAttributes(typeof(ReadOnlyCustomAttribute), false);
                    var v = property.GetValue(org, null);
                    if ((notUpdate == null || notUpdate.Length == 0) && (readOnlyCustom == null || readOnlyCustom.Length == 0))
                    {
                        if (property.Name.ToLower() != "ou")
                        {
                            if (v == null)
                            {
                                orgDe.Properties[property.Name].Clear();
                            }
                            else
                            {
                                orgDe.Properties[property.Name].Value = v;
                            }
                        }

                    }
                }
            }
            orgDe.CommitChanges();
            //如果OU有值则执行修改
            if (!string.IsNullOrWhiteSpace(org.Ou))
            {
                orgDe.Rename("ou=" + org.Ou);
                orgDe.CommitChanges();
            }
            return true;
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="orgDe">需要删除的组织信息</param>
        /// <returns>成功True，失败False</returns>
        public bool Delete(DirectoryEntry orgDe)
        {
            orgDe.DeleteTree();
            return true;
        }

        /// <summary>
        /// 移动
        /// </summary>
        /// <param name="parentOrgDe">移动的目标组织</param>
        /// <param name="orgDe">需要移动的组织</param>
        /// <returns>成功True，失败False</returns>
        public bool Move(DirectoryEntry parentOrgDe, DirectoryEntry org)
        {
            org.MoveTo(parentOrgDe);
            return true;
        }
    }
}
